package com.cucn.ingmall.cart.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.cucn.common.utils.R;
import com.cucn.ingmall.cart.dto.UserInfoDTO;
import com.cucn.ingmall.cart.feign.ProductFeignService;
import com.cucn.ingmall.cart.interceptor.CartInterceptor;
import com.cucn.ingmall.cart.service.CartService;
import com.cucn.ingmall.cart.vo.Cart;
import com.cucn.ingmall.cart.vo.CartItem;
import com.cucn.ingmall.cart.vo.SkuInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author KouChaoJie
 * @since: 2022/1/14 10:23
 */
@Slf4j
@Service
public class CartServiceImpl implements CartService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private ProductFeignService productFeignService;
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    /**
     * 购物车redis的key的前缀
     */
    private final String CART_PREFIX = "ingmall:cart:";

    /**
     * 用户添加商品到购物车
     *
     * @param skuId  商品id
     * @param skuNum 商品数量
     * @return 购物车购物项
     */
    @Override
    public CartItem addToCart(Long skuId, Integer skuNum) throws ExecutionException, InterruptedException {
        //1. 2. 获取到当前购物车的redis操作
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();

        //从redis里查询当前商品
        String redisCart = (String) cartOps.get(skuId.toString());

        if (StringUtils.isEmpty(redisCart)) {
            log.info("添加新商品到购物车");
            //redis查询结果如果为空,是新商品
            //添加新商品到购物车
            CartItem cartItem = new CartItem();

            //异步编排优化
            //远程调用,查询商品的详细信息
            CompletableFuture<Void> getSkunInfoTask = CompletableFuture.runAsync(() -> {
                R skuFeign = productFeignService.info(skuId);
                SkuInfo skuInfo = skuFeign.getData("skuInfo", new TypeReference<SkuInfo>() {
                });

                cartItem.setId(skuId);
                cartItem.setPrice(skuInfo.getPrice());
                cartItem.setDefaultImage(skuInfo.getSkuDefaultImg());
                cartItem.setTitle(skuInfo.getSkuTitle());
                cartItem.setCount(skuNum);
            }, threadPoolExecutor);

            //远程调用,查询sku销售属性组合信息
            CompletableFuture<Void> getSkuSaleAttrTask = CompletableFuture.runAsync(() -> {
                List<String> skuSaleAttrValues = productFeignService.getSkuSaleAttrValues(skuId);
                cartItem.setSkuAttr(skuSaleAttrValues);
            }, threadPoolExecutor);
            CompletableFuture.allOf(getSkunInfoTask, getSkuSaleAttrTask).get();

            //将商品信息存入redis,key为skuId,值为商品信息的json字符串
            cartOps.put(skuId.toString(), JSON.toJSONString(cartItem));

            return cartItem;
        } else {
            log.info("添加已有商品到购物车,更新redis....");
            //不为空,购物车里已经有商品,只需更新数量即可
            CartItem cartItem = JSON.parseObject(redisCart, CartItem.class);
            cartItem.setCount(cartItem.getCount() + skuNum);
            cartOps.put(skuId.toString(), JSON.toJSONString(cartItem));

            return cartItem;
        }
    }

    /**
     * 添加商品到购物车成功页
     *
     * @param skuId
     * @return
     */
    @Override
    public CartItem getSuccessCart(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();

        String redisCart = (String) cartOps.get(skuId.toString());
        CartItem cartItem = JSON.parseObject(redisCart, CartItem.class);

        return cartItem;
    }

    /**
     * 获取购物车内容
     *
     * @return 当前用户的购物车内容
     */
    @Override
    public Cart getCart() throws ExecutionException, InterruptedException {
        Cart cart = new Cart();
        UserInfoDTO userInfo = CartInterceptor.threadlocal.get();

        String cartKey;
        if (userInfo.getUserId() != null) {
            //登录状态购物车,需要和临时购物车合并
            cartKey = CART_PREFIX + userInfo.getUserId();
            String tempCartKey = CART_PREFIX + userInfo.getUserKeyValue();

            //当前用户对应的临时购物车是否有商品?有则合并
            List<CartItem> tempCartItems = getCartItems(tempCartKey);
            if (!CollectionUtils.isEmpty(tempCartItems)) {
                //临时购物车合并到用户购物车
                for (CartItem tempCartItem : tempCartItems) {
                    addToCart(tempCartItem.getId(), tempCartItem.getCount());
                }
                //合并完成,清除临时购物车数据
                clearCart(tempCartKey);
            }

            //获取用户购物车[包含合并的临时购物车数据]
            List<CartItem> userCartItems = getCartItems(cartKey);
            cart.setItems(userCartItems);

        } else {
            //没登录,游客购物车
            cartKey = CART_PREFIX + userInfo.getUserKeyValue();
            List<CartItem> cartItems = getCartItems(cartKey);
            cart.setItems(cartItems);
        }

        return cart;
    }

    /**
     * 获取购物车里所有的购物项
     *
     * @param cartKey 键
     * @return
     */
    private List<CartItem> getCartItems(String cartKey) {
        BoundHashOperations<String, Object, Object> ops = stringRedisTemplate.boundHashOps(cartKey);
        //获取所有购物项
        List<Object> cartValues = ops.values();
        List<CartItem> cartItems;
        if (!CollectionUtils.isEmpty(cartValues)) {
            cartItems = cartValues.stream().map(obj -> {
                String cartValue = (String) obj;
                return JSON.parseObject(cartValue, CartItem.class);
            }).collect(Collectors.toList());
            return cartItems;
        }
        return null;
    }

    /**
     * 获取到当前购物车的redis操作
     *
     * @return 当前线程购物车操作
     */
    private BoundHashOperations<String, Object, Object> getCartOps() {
        //1.判断是用户登录购物车还是游客离线购物车
        UserInfoDTO userInfoDTO = CartInterceptor.threadlocal.get();

        //2.redis里存储的key的格式规定：cart:用户id/临时用户cookie值
        String cartKey;
        if (userInfoDTO.getUserId() == null) {
            cartKey = CART_PREFIX + userInfoDTO.getUserKeyValue();
            log.info("临时用户:{},添加商品到购物车", userInfoDTO.getUserKeyValue());
        } else {
            cartKey = CART_PREFIX + userInfoDTO.getUserId();
            log.info("{}号用户,添加商品到购物车", userInfoDTO.getUserId());
        }

        //将redis操作绑定key值
        return stringRedisTemplate.boundHashOps(cartKey);
    }

    /**
     * 清空购物车数据
     *
     * @param cartKey 购物车的key
     */
    @Override
    public void clearCart(String cartKey) {
        stringRedisTemplate.delete(cartKey);
    }

    /**
     * 修改选中状态
     *
     * @param skuId
     * @param checked 是否选中?
     */
    @Override
    public void updateCartItemCheck(Long skuId, Integer checked) {
        BoundHashOperations<String, Object, Object> ops = getCartOps();
        //拿到redis里skuId购物项
        CartItem cartItem = getSuccessCart(skuId);
        cartItem.setCheck(checked == 1);
        String cartItemJsonString = JSON.toJSONString(cartItem);
        //更新选中状态
        ops.put(skuId.toString(), cartItemJsonString);
    }

    /**
     * 修改购物项的商品数量
     *
     * @param skuId
     * @param num   商品数量
     */
    @Override
    public void updateCartItemCount(Long skuId, Integer num) {
        BoundHashOperations<String, Object, Object> ops = getCartOps();
        CartItem cartItem = getSuccessCart(skuId);
        cartItem.setCount(num);
        String cartItemJsonString = JSON.toJSONString(cartItem);
        //更新选中状态
        ops.put(skuId.toString(), cartItemJsonString);
    }

    @Override
    public void deleteCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> ops = getCartOps();
        ops.delete(skuId.toString());
    }

    /**
     * 获取选中的购物项
     *
     * @return
     */
    @Override
    public List<CartItem> getCheckItems() {
        UserInfoDTO userInfo = CartInterceptor.threadlocal.get();
        if (userInfo.getUserId() == null) {
            return null;
        } else {
            String cartKey = CART_PREFIX + userInfo.getUserId().toString();
            List<CartItem> cartItems = getCartItems(cartKey);

            //获取所有被选中的购物项
            List<CartItem> cartItemList = cartItems.stream()
                    .filter(CartItem::getCheck)
                    //购物项的价格需要更新
                    .map(cartItem -> {
                        R priceR = productFeignService.getPrice(cartItem.getId());
                        BigDecimal price = priceR.getData(new TypeReference<BigDecimal>() {
                        });
                        cartItem.setPrice(price);
                        return cartItem;
                    })
                    .collect(Collectors.toList());

            return cartItemList;
        }
    }
}
